#ifndef _POLYGONALMESH_H_
#define _POLYGONALMESH_H_

#include <cmath>
#include <cstdio>
#include <vector>
#include "RTree.h"
#include <GL/gl.h>
#include <opencv/cxcore.h>

class Patch
{
public:
  Patch(GLuint textureId, double x1, double y1, double x2, double y2, double x3, double y3, void *data = NULL)
  {
    this->gluTextureId = textureId;
    this->x1 = x1;
    this->y1 = y1;
    this->x2 = x2;
    this->y2 = y2;
    this->x3 = x3;
    this->y3 = y3;
    this->data = data;
  }

  GLuint gluTextureId;
  float x1, y1;
  float x2, y2;
  float x3, y3;
  void *data;

private:
  // Do not allow copy
  Patch(const Patch& k);
  Patch& operator=(const Patch&);
};

class Face {
public:
  Face(float x1, float y1, float z1, float x2, float y2, float z2, float x3, float y3, float z3, bool b1, bool b2, bool b3, float xc, float yc, float zc, float xn, float yn, float zn)
  {
    this->x1 = x1;
    this->y1 = y1;
    this->z1 = z1;
    this->x2 = x2;
    this->y2 = y2;
    this->z2 = z2;
    this->x3 = x3;
    this->y3 = y3;
    this->z3 = z3;
    this->b1 = b1;
    this->b2 = b2;
    this->b3 = b3;
    this->xc = xc;
    this->yc = yc;
    this->zc = zc;
    this->xn = xn;
    this->yn = yn;
    this->zn = zn;
  }

  ~Face()
  {
    for(unsigned int i = 0; i < patches.size(); ++i)
      delete patches[i];
    patches.clear();
  }

  // Is the vertex on the boundary
  bool b1;
  bool b2;
  bool b3;

  // Vertex positions in world coordinates
  float x1, y1, z1;
  float x2, y2, z2;
  float x3, y3, z3;

  // Face normal and center
  float xn, yn, zn;
  float xc, yc, zc;

  // Image patches for texture (projection of face into nearby images)
  std::vector<Patch*> patches;

private:
  // Do not allow copy
  Face(const Face& k);
  Face& operator=(const Face&);
};

class Cube {
public:
  Cube() 
  { 
    score = 0.0; 
  }
  ~Cube()
  {
    for(unsigned int i = 0; i < faces.size(); ++i)
      delete faces[i];
    faces.clear();
  }
  std::vector<Face*> faces;
  float score;

private:
  // Do not allow copy
  Cube(const Cube& k);
  Cube& operator=(const Cube&);
};

class PolygonalMesh  
{
public:
	PolygonalMesh();
	virtual ~PolygonalMesh();

  void Reset();
  double GetGridSize() { return mdGridSize; }
	
  void RemoveCube(int ci, int cj, int ck);
  void RemoveCubes(int cimin, int cjmin, int ckmin, int cimax, int cjmax, int ckmax);

  void SetCube(int ci, int cj, int ck, boost::shared_ptr<Cube> c);

  boost::shared_ptr<Cube> GetCube(int ci, int cj, int ck);
  int GetCubes(int cimin, int cjmin, int ckmin, int cimax, int cjmax, int ckmax, std::vector<boost::shared_ptr<Cube> > &c);

  int GetCubes(float xmin, float ymin, float zmin, float xmax, float ymax, float zmax, std::vector<boost::shared_ptr<Cube> > &c);
  int GetAllCubes(std::vector<boost::shared_ptr<Cube> >& c);

private:
  double mdGridSize;

  RTree<Cube, int, 3> rtpCubes;
};

#endif
